Step 2: Evaluate output
include_graphics("prsice_images/TERRE_PRSice_BARPLOT_2022-06-30.png")

include_graphics("prsice_images/TERRE_PRSice_HIGH-RES_PLOT_2022-06-30.png")

include_graphics("prsice_images/TERRE_PRSice_QUANTILES_PLOT_2022-06-30.png")

include_graphics("prsice_images/TERRE_PRSice_nalls_male_BARPLOT_2022-06-30.png")

include_graphics("prsice_images/TERRE_PRSice_nalls_male_HIGH-RES_PLOT_2022-06-30.png")

include_graphics("prsice_images/TERRE_PRSice_nalls_male_QUANTILES_PLOT_2022-06-30.png")

include_graphics("prsice_images/TERRE_PRSice_nalls_female_BARPLOT_2022-06-30.png")

include_graphics("prsice_images/TERRE_PRSice_nalls_female_HIGH-RES_PLOT_2022-06-30.png")

include_graphics("prsice_images/TERRE_PRSice_nalls_female_QUANTILES_PLOT_2022-06-30.png")

Plotting PRSice Data on my own
library(ggnewscale)
prsice_male_meta <- fread("prsice_nalls_male_data/TERRE_PRSice_nalls_male.prsice")
ggplot(prsice_male_meta[Threshold <= 0.5], aes(Threshold, Num_SNP, color = -log10(P))) +
geom_point() +
scale_y_continuous(breaks = c(seq(0, 1e5, 2.5e4), seq(2e5, 6e5, 1e5))) +
theme_minimal()

prsice_female_meta <- fread("prsice_nalls_female_data/TERRE_PRSice_nalls_female.prsice")
ggplot(prsice_female_meta[Threshold <= 0.5], aes(Threshold, Num_SNP, color = -log10(P))) +
geom_point() +
scale_y_continuous(breaks = c(seq(0, 1e5, 2.5e4), seq(2e5, 6e5, 1e5))) +
theme_minimal()

prsice_meta <- fread("prsice_data/TERRE_PRSice.prsice")
ggplot(mapping = aes(Threshold, R2, color = -log10(P))) +
geom_point(data = prsice_female_meta, size = 1) +
scale_color_gradient(low = "lightpink4", high = "lightpink") +
labs(color = bquote("Female log"["10"] ~ "(P)")) +
new_scale_color() +
geom_point(data = prsice_male_meta, size = 1, aes(color = -log10(P))) +
scale_color_gradient(low = "lightblue4", high = "lightblue") +
labs(y = bquote("R"^2), x = "GWAS P-Value Threshold", color = bquote("Male log"["10"] ~ "(P)")) +
theme_minimal() +
theme(legend.position = "top")

ggplot(mapping = aes(Threshold, R2, color = -log10(P))) +
geom_point(data = prsice_female_meta, size = 1) +
scale_color_gradient(low = "lightpink4", high = "lightpink") +
labs(color = bquote("Female log"["10"] ~ "(P)")) +
new_scale_color() +
geom_point(data = prsice_male_meta, size = 1, aes(color = -log10(P))) +
scale_color_gradient(low = "lightblue4", high = "lightblue") +
labs(color = bquote("Male log"["10"] ~ "(P)")) +
new_scale_color() +
geom_point(data = prsice_meta, size = 1, aes(color = -log10(P))) +
scale_color_gradient(low = "gray40", high = "gray80") +
labs(y = bquote("R"^2), x = "GWAS P-Value Threshold", color = bquote("Cross-sex -log"["10"] ~ "(P)")) +
theme_minimal() +
theme(legend.position = "top")

Step 3 run linear model at different thresholds for SNP inclusion
load("/home1/NEURO/SHARE_DECIPHER/processed_DNAm_data/TERRE_processed_2021/betas_combat.RData") # betas_sub
# Assign genotyping ID to data
original_covars <- fread("/home1/NEURO/SHARE_DECIPHER/terre_meta_master.csv")[, .(patient, IID = gsub("_PAE.*", "", IID))]
colnames(betas_combat) <- original_covars$IID[match(colnames(betas_combat), original_covars$patient)]
betas_combat <- betas_combat[, colnames(betas_combat) %in% covariate$IID]
Let’s check how the data looks for the first 5 subjects:
ggplot(betas_combat[, 1:5] %>% as.data.table(keep.rownames = T) %>% melt(id.vars = "rn", value.name = "betas", variable.name = "subject"), aes(betas, color = subject)) +
geom_density()

Match DNA, PRS, and metadata
prsice_all <- fread("prsice_data/TERRE_PRSice.all_score")[match(colnames(betas_combat), IID), .(FID, IID, `Pt_0.0219001`, `Pt_5e-08`, `Pt_5.005e-05`, `Pt_0.00010005`, `Pt_0.00100005`, `Pt_0.0101501`, `Pt_0.1`, `Pt_0.2`, `Pt_0.3`, `Pt_0.4`, `Pt_0.5`, `Pt_1`)]
covariate <- covariate[match(colnames(betas_combat), IID)]
all(covariate$IID == colnames(betas_combat))
[1] TRUE
all(covariate$IID == prsice_all$IID)
[1] TRUE
covariate_male <- covariate[sex == 1] %>% select(-sex)
betas_male <- betas_combat[, covariate_male$IID]
prsice_male_all <- prsice_all[match(colnames(betas_male), IID), .(FID, IID, `Pt_0.0219001`, `Pt_5e-08`, `Pt_5.005e-05`, `Pt_0.00010005`, `Pt_0.00100005`, `Pt_0.0101501`, `Pt_0.1`, `Pt_0.2`, `Pt_0.3`, `Pt_0.4`, `Pt_0.5`, `Pt_1`)]
covariate_male <- covariate_male[match(colnames(betas_male), IID)]
all(covariate_male$IID == colnames(betas_male))
[1] TRUE
all(covariate_male$IID == prsice_male_all$IID)
[1] TRUE
covariate_female <- covariate[sex == 0] %>% select(-sex)
betas_female <- betas_combat[, covariate_female$IID]
prsice_female_all <- prsice_all[match(colnames(betas_female), IID), .(FID, IID, `Pt_0.0219001`, `Pt_5e-08`, `Pt_5.005e-05`, `Pt_0.00010005`, `Pt_0.00100005`, `Pt_0.0101501`, `Pt_0.1`, `Pt_0.2`, `Pt_0.3`, `Pt_0.4`, `Pt_0.5`, `Pt_1`)]
covariate_female <- covariate_female[match(colnames(betas_female), IID)]
all(covariate_female$IID == colnames(betas_female))
[1] TRUE
all(covariate_female$IID == prsice_female_all$IID)
[1] TRUE
covariate_male <- covariate[sex == 1] %>% select(-sex)
betas_male <- betas_combat[, covariate_male$IID]
prsice_male_nalls_all <- fread("prsice_nalls_male_data/TERRE_PRSice_nalls_male.all_score")[match(colnames(betas_male), IID), .(FID, IID, `Pt_0.0219001`, `Pt_5e-08`, `Pt_5.005e-05`, `Pt_0.00010005`, `Pt_0.00100005`, `Pt_0.0101501`, `Pt_0.1`, `Pt_0.2`, `Pt_0.3`, `Pt_0.4`, `Pt_0.5`, `Pt_1`)]
covariate_male <- covariate_male[match(colnames(betas_male), IID)]
all(covariate_male$IID == colnames(betas_male))
[1] TRUE
all(covariate_male$IID == prsice_male_nalls_all$IID)
[1] TRUE
covariate_female <- covariate[sex == 0] %>% select(-sex)
betas_female <- betas_combat[, covariate_female$IID]
prsice_female_nalls_all <- fread("prsice_nalls_female_data/TERRE_PRSice_nalls_female.all_score")[match(colnames(betas_female), IID), .(FID, IID, `Pt_0.0219001`, `Pt_5e-08`, `Pt_5.005e-05`, `Pt_0.00010005`, `Pt_0.00100005`, `Pt_0.0101501`, `Pt_0.1`, `Pt_0.2`, `Pt_0.3`, `Pt_0.4`, `Pt_0.5`, `Pt_1`)]
covariate_female <- covariate_female[match(colnames(betas_female), IID)]
all(covariate_female$IID == colnames(betas_female))
[1] TRUE
all(covariate_female$IID == prsice_female_nalls_all$IID)
[1] TRUE
Run limma
mvalues <- lumi::beta2m(betas_combat)
prs_mat <- prsice_all[, -c(1, 2)]
cov_mat <- covariate[, -c(1, 2)]
mvalues_male <- lumi::beta2m(betas_male)
prs_mat_male <- prsice_male_all[, -c(1, 2)]
cov_mat_male <- covariate_male[, -c(1, 2)]
mvalues_female <- lumi::beta2m(betas_female)
prs_mat_female <- prsice_female_all[, -c(1, 2)]
cov_mat_female <- covariate_female[, -c(1, 2)]
prs_mat_nalls_male <- prsice_male_nalls_all[, -c(1, 2)]
prs_mat_nalls_female <- prsice_female_nalls_all[, -c(1, 2)]
registerDoParallel(ncol(prs_mat) / 2)
hits <- foreach(prs_thresh = colnames(prs_mat)) %dopar% {
design_prs <- model.matrix(~., data = cbind(prs_mat[, ..prs_thresh], cov_mat))
prs_fit <- lmFit(mvalues, design_prs)
prs_fit <- eBayes(prs_fit)
topTable(prs_fit, coef = 2, adjust.method = "bonf", p.value = 0.05, number = Inf, genelist = rownames(mvalues))
}
names(hits) <- colnames(prs_mat)
hits_by_thresh_bonf <- rbindlist(hits, idcol = "threshold", fill = TRUE)
registerDoParallel(ncol(prs_mat_male) / 2)
hits_male <- foreach(prs_thresh = colnames(prs_mat_male)) %dopar% {
design_prs_male <- model.matrix(~., data = cbind(prs_mat_male[, ..prs_thresh], cov_mat_male))
prs_fit_male <- lmFit(mvalues_male, design_prs_male)
prs_fit_male <- eBayes(prs_fit_male)
topTable(prs_fit_male, coef = 2, adjust.method = "bonf", p.value = 0.05, number = Inf, genelist = rownames(mvalues_male))
}
names(hits_male) <- colnames(prs_mat_male)
hits_by_thresh_bonf_male <- rbindlist(hits_male, idcol = "threshold", fill = TRUE)
registerDoParallel(ncol(prs_mat_female) / 2)
hits_female <- foreach(prs_thresh = colnames(prs_mat_female)) %dopar% {
design_prs_female <- model.matrix(~., data = cbind(prs_mat_female[, ..prs_thresh], cov_mat_female))
prs_fit_female <- lmFit(mvalues_female, design_prs_female)
prs_fit_female <- eBayes(prs_fit_female)
topTable(prs_fit_female, coef = 2, adjust.method = "bonf", p.value = 0.05, number = Inf, genelist = rownames(mvalues_female))
}
names(hits_female) <- colnames(prs_mat_female)
hits_by_thresh_bonf_female <- rbindlist(hits_female, idcol = "threshold", fill = TRUE)
registerDoParallel(ncol(prs_mat_male) / 2)
hits_nalls_male <- foreach(prs_thresh = colnames(prs_mat_nalls_male)) %dopar% {
design_prs_nalls_male <- model.matrix(~., data = cbind(prs_mat_nalls_male[, ..prs_thresh], cov_mat_male))
prs_fit_nalls_male <- lmFit(mvalues_male, design_prs_nalls_male)
prs_fit_nalls_male <- eBayes(prs_fit_nalls_male)
topTable(prs_fit_nalls_male, coef = 2, adjust.method = "bonf", p.value = 0.05, number = Inf, genelist = rownames(mvalues_male))
}
names(hits_nalls_male) <- colnames(prs_mat_nalls_male)
hits_by_thresh_bonf_nalls_male <- rbindlist(hits_nalls_male, idcol = "threshold", fill = TRUE)
registerDoParallel(ncol(prs_mat_female) / 2)
hits_nalls_female <- foreach(prs_thresh = colnames(prs_mat_nalls_female)) %dopar% {
design_prs_nalls_female <- model.matrix(~., data = cbind(prs_mat_nalls_female[, ..prs_thresh], cov_mat_female))
prs_fit_nalls_female <- lmFit(mvalues_female, design_prs_nalls_female)
prs_fit_nalls_female <- eBayes(prs_fit_nalls_female)
topTable(prs_fit_nalls_female, coef = 2, adjust.method = "bonf", p.value = 0.05, number = Inf, genelist = rownames(mvalues_female))
}
names(hits_nalls_female) <- colnames(prs_mat_nalls_female)
hits_by_thresh_bonf_nalls_female <- rbindlist(hits_nalls_female, idcol = "threshold", fill = TRUE)
Plotting EWAS vs Threshold Experiment by Sex
to_plot <- rbind(
hits_by_thresh_bonf[, .(hits = .N, Sex = "Cross-sex"), by = threshold] %>%
mutate(threshold = recode_factor(threshold, `Pt_0.0219001` = "0.0219", `Pt_5e-08` = "5e-8", `Pt_5.005e-05` = "5e-5", `Pt_0.00010005` = "1e-4", `Pt_0.00100005` = "1e-3", `Pt_0.0101501` = "1e-2", `Pt_0.1` = "0.1", `Pt_0.2` = "0.2", `Pt_0.3` = "0.3", `Pt_0.4` = "0.4", `Pt_0.5` = "0.5", `Pt_1` = "1.0")),
hits_by_thresh_bonf_nalls_male[, .(hits = .N, Sex = "Male"), by = threshold] %>%
mutate(threshold = recode_factor(threshold, `Pt_0.0219001` = "0.0219", `Pt_5e-08` = "5e-8", `Pt_5.005e-05` = "5e-5", `Pt_0.00010005` = "1e-4", `Pt_0.00100005` = "1e-3", `Pt_0.0101501` = "1e-2", `Pt_0.1` = "0.1", `Pt_0.2` = "0.2", `Pt_0.3` = "0.3", `Pt_0.4` = "0.4", `Pt_0.5` = "0.5", `Pt_1` = "1.0")),
hits_by_thresh_bonf_nalls_female[, .(hits = .N, Sex = "Female"), by = threshold] %>%
mutate(threshold = recode_factor(threshold, `Pt_0.0219001` = "0.0219", `Pt_5e-08` = "5e-8", `Pt_5.005e-05` = "5e-5", `Pt_0.00010005` = "1e-4", `Pt_0.00100005` = "1e-3", `Pt_0.0101501` = "1e-2", `Pt_0.1` = "0.1", `Pt_0.2` = "0.2", `Pt_0.3` = "0.3", `Pt_0.4` = "0.4", `Pt_0.5` = "0.5", `Pt_1` = "1.0"))
) %>% mutate(Sex = factor(Sex, levels = c("Cross-sex", "Male", "Female")))
plot_pos <- position_dodge(width = 1)
ggplot(to_plot, aes(threshold, hits, fill = Sex, label = hits)) +
geom_text(position = plot_pos, vjust = -0.25) +
geom_col(position = plot_pos) +
labs(x = "GWAS P Value Threshold", y = "EWAS Hits") +
scale_fill_manual(values = c("grey80", "lightblue", "lightpink")) +
theme_minimal()

hits_by_thresh_bonf[, .(hits = .N, Sex = "Cross-sex"), by = threshold]
hits_by_thresh_bonf_nalls_male[, .(hits = .N), by = threshold]
hits_by_thresh_bonf_nalls_female[, .(hits = .N), by = threshold]
display_venn <- function(x, ...) {
library(VennDiagram)
grid.newpage()
venn_object <- venn.diagram(x, filename = NULL, ...)
grid.draw(venn_object)
}
display_venn(list(`Cross-sex` = hits_by_thresh_bonf[threshold == "Pt_5e-08"]$ID, Male = hits_by_thresh_bonf_nalls_male[threshold == "Pt_5e-08"]$ID, Female = hits_by_thresh_bonf_nalls_female[threshold == "Pt_5e-08"]$ID), fill = c("gray80", "lightblue", "lightpink"))
Loading required package: grid
Loading required package: futile.logger

male_ids <- hits_by_thresh_bonf_nalls_male[threshold == "Pt_5e-08"]$ID
cross_ids <- hits_by_thresh_bonf[threshold == "Pt_5e-08"]$ID
male_ids[!male_ids %in% cross_ids]
character(0)
library(missMethyl)
gometh(hits_by_thresh_bonf[threshold == "Pt_5e-08"]$ID, array.type = "EPIC", all.cpg = rownames(mvalues))
get_full_fit <- function(prs_mat,cov_mat,mvalues){
top_design_prs <- model.matrix(~., data = cbind(prs_mat[, `Pt_5e-08`], cov_mat))
top_prs_fit <- lmFit(mvalues, top_design_prs)
top_prs_fit <- eBayes(top_prs_fit)
top_prs_hits <- topTable(top_prs_fit, coef = 2, adjust.method = "bonf", number = Inf, genelist = rownames(mvalues))
}
top_prs_hits <- get_full_fit(prs_mat,cov_mat,mvalues)
top_male_prs_hits <- get_full_fit(prs_mat_nalls_male, cov_mat_male, mvalues_male)
top_female_prs_hits <- get_full_fit(prs_mat_nalls_female, cov_mat_female, mvalues_female)
manifest <- IlluminaHumanMethylationEPICanno.ilm10b4.hg19::Other %>%
as.data.frame() %>%
rownames_to_column(var = "name")
prs_annot <- data.table(top_prs_hits)[manifest, gene := gsub(";.*", "", UCSC_RefGene_Name), on = c(ID = "name")]
prs_annot_male <- data.table(top_male_prs_hits)[manifest, gene := gsub(";.*", "", UCSC_RefGene_Name), on = c(ID = "name")]
prs_annot_female<- data.table(top_female_prs_hits)[manifest, gene := gsub(";.*", "", UCSC_RefGene_Name), on = c(ID = "name")]
plot_prs_hits <- function(prs_annot,label_color){
ggplot(prs_annot, aes(logFC, -log10(P.Value))) +
geom_point() +
geom_point(
data = subset(prs_annot, adj.P.Val < 0.05 & abs(logFC) > 0.03),
color = label_color,
mapping = aes(logFC, -log10(P.Value))
) +
geom_hline(
linetype = "dashed",
yintercept = min(-log10(prs_annot$P.Value[prs_annot$adj.P.Val < 0.05]))
) +
geom_vline(linetype = "dashed", xintercept = 0.03) +
geom_vline(linetype = "dashed", xintercept = -0.03) +
geom_text_repel(
data = prs_annot %>% filter(abs(logFC) > 0.03 & adj.P.Val < 0.05),
color = "dodgerblue",
mapping = aes(logFC, -log10(P.Value), label = ifelse(gene != "", gene, ID)),
size = 3,
max.overlaps = 20
) +
labs(y = bquote("log"[10] ~ "(P)"), x = quote(Delta ~ "M" ~ Methylation)) +
theme_minimal()
}
plot_prs_hits(prs_annot,"gray40")

plot_prs_hits(prs_annot_male,"lightblue")

plot_prs_hits(prs_annot_female,"pink")

manifest[manifest$name =="cg06846282",]
Manhattan plot vs GWAS manhattan plot
library(qqman)
cpg_pos <- IlluminaHumanMethylationEPICanno.ilm10b4.hg19::Locations %>%
as.data.frame() %>%
rownames_to_column(var = "name")
copy_annot <- prs_annot[cpg_pos, on = c(ID = "name")] %>%
mutate(chr = as.numeric(recode(gsub("chr", "", chr),X="23",Y="24")))
to_plot <- copy_annot[, .(SNP = gene, CHR = chr, BP = pos, P = P.Value, FDR = adj.P.Val)][!is.na(P)]
manhattan(to_plot,
annotatePval = max(to_plot[FDR < 0.05]$P),
annotateTop = TRUE,
genomewideline = min(-log10(to_plot[FDR < 0.05]$P)),
suggestiveline = FALSE
)
manhattan(to_plot[CHR == 17],
annotatePval = max(to_plot[FDR < 0.05]$P),
annotateTop = FALSE,
genomewideline = min(-log10(to_plot[FDR < 0.05]$P)),
suggestiveline = FALSE
)
qq(to_plot$P)
GWAS <- fread("~/nalls_PD.QC.gz")
manhattan(GWAS,
annotatePval = 5e-8,
bp = "POS",
p = "p",
suggestiveline = FALSE
)
DMRs
library(DMRcate)
S4_to_dataframe <- function(s4obj) {
nms <- slotNames(s4obj)
lst <- lapply(nms, function(nm) slot(s4obj, nm))
as.data.frame(setNames(lst, nms))
}
run_dmrcate <- function(prs_mat,cov_mat,mvalues){
design_prs <- model.matrix(~., data = cbind(prs_mat[, `Pt_5e-08`], cov_mat))
prs_annotated <- cpg.annotate(datatype = "array", object = mvalues, analysis.type = "differential", design = design_prs, coef = 2, what = "M", arraytype = "EPIC", fdr = 0.05)
prs_dmr_res <- dmrcate(prs_annotated, lambda = 1000, C = 2)
return(S4_to_dataframe(prs_dmr_res))
}
dmr_cross <- run_dmrcate(prs_mat, cov_mat, mvalues)
Your contrast returned 73 individually significant probes; a small but real effect. Consider manually setting the value of pcutoff to return more DMRs, but be warned that doing this increases the risk of Type I errors.
Fitting chr1...
Fitting chr2...
Fitting chr3...
Fitting chr4...
Fitting chr5...
Fitting chr6...
Fitting chr7...
Fitting chr8...
Fitting chr9...
Fitting chr10...
Fitting chr11...
Fitting chr12...
Fitting chr13...
Fitting chr14...
Fitting chr15...
Fitting chr16...
Fitting chr17...
Fitting chr18...
Fitting chr19...
Fitting chr20...
Fitting chr21...
Fitting chr22...
Fitting chrX...
Fitting chrY...
Demarcating regions...
Done!
dmr_males <- run_dmrcate(prs_mat_nalls_male,cov_mat_male,mvalues_male)
Your contrast returned 60 individually significant probes; a small but real effect. Consider manually setting the value of pcutoff to return more DMRs, but be warned that doing this increases the risk of Type I errors.
Fitting chr1...
Fitting chr2...
Fitting chr3...
Fitting chr4...
Fitting chr5...
Fitting chr6...
Fitting chr7...
Fitting chr8...
Fitting chr9...
Fitting chr10...
Fitting chr11...
Fitting chr12...
Fitting chr13...
Fitting chr14...
Fitting chr15...
Fitting chr16...
Fitting chr17...
Fitting chr18...
Fitting chr19...
Fitting chr20...
Fitting chr21...
Fitting chr22...
Fitting chrX...
Fitting chrY...
Demarcating regions...
Done!
dmr_female <- run_dmrcate(prs_mat_nalls_female,cov_mat_female,mvalues_female)
Your contrast returned 27 individually significant probes; a small but real effect. Consider manually setting the value of pcutoff to return more DMRs, but be warned that doing this increases the risk of Type I errors.
Fitting chr1...
Fitting chr2...
Fitting chr3...
Fitting chr4...
Fitting chr5...
Fitting chr6...
Fitting chr7...
Fitting chr8...
Fitting chr9...
Fitting chr10...
Fitting chr11...
Fitting chr12...
Fitting chr13...
Fitting chr14...
Fitting chr15...
Fitting chr16...
Fitting chr17...
Fitting chr18...
Fitting chr19...
Fitting chr20...
Fitting chr21...
Fitting chr22...
Fitting chrX...
Fitting chrY...
Demarcating regions...
Done!
annotation <- minfi::getAnnotation(IlluminaHumanMethylationEPICanno.ilm10b4.hg19)
Plotting all DMRs
get_dmr_effects <- function(dmr, limma_res,mvalues) {
dmr_coord <- str_match_all(as.character(dmr), "(chr.*):([0-9]*)-([0-9]*)")[[1]]
cpgs <- as.data.table(annotation[annotation$chr == dmr_coord[2] & annotation$pos >= as.numeric(dmr_coord[3]) & annotation$pos <= as.numeric(dmr_coord[4]), ])
res <- limma_res[cpgs,on=c("ID"="Name"),nomatch=0 ]
dmr_1 <- as.data.frame(res[!is.na(res$logFC), ])
dmr_methy <- reshape2::melt(lumi::m2beta(mvalues[dmr_1$ID, ]), stringsAsFactors = FALSE)
to_plot <- merge(dmr_1, dmr_methy, by.x = "ID", by.y = "Var1")
to_plot$DMR <- dmr
to_plot
}
get_dmr_res <- function(dmr, limma_res) {
dmr_coord <- str_match_all(as.character(dmr), "(chr.*):([0-9]*)-([0-9]*)")[[1]]
cpgs <- annotation[annotation$chr == dmr_coord[2] & annotation$pos >= as.numeric(dmr_coord[3]) & annotation$pos <= as.numeric(dmr_coord[4]), ]
res <- cbind(cpgs, limma_res[cpgs$Name, ])
res$DMR <- dmr
return(res)
}
plot_dmrs <- function(dmr_res,limma_res,prs_mat, mvalues, case_control) {
to_plot <- rbindlist(lapply(dmr_res$coord, function(dmr) get_dmr_effects(dmr, limma_res,mvalues))) %>%
mutate(SCORE1_AVG = scale(prs_mat[match(Var2,IDs$IID),`Pt_5e-08`]),PD = PD[match(Var2,IID)]$PD) %>%
filter(!is.na(SCORE1_AVG))
for(cur_dmr in unique(to_plot$DMR)){
cur_plot <- to_plot[DMR == cur_dmr]
p1 <- ggplot(cur_plot , aes(pos, value, color = SCORE1_AVG)) +
geom_point() +
scale_color_gradient(low = rev(case_control)[1], high = rev(case_control)[2]) +
theme_minimal() +
labs(title = unique(cur_plot$DMR),x="POS",y=bquote("Methylation"~beta),color = "Normalized PD PRS")+
theme(axis.text.x = element_text(angle = 90))
p2 <- ggplot(cur_plot %>% mutate(PD = ifelse(PD == 1, "CASE", "CONTROL")), aes(factor(pos), value, color = PD)) +
geom_boxplot(position = position_dodge(0.75)) +
scale_color_manual(values = case_control) +
theme_minimal() +
stat_summary(aes(group = PD), fun = mean, geom = "line") +
labs(title = unique(cur_plot$DMR),x="POS",y=bquote("Methylation"~beta),color = "PD status") +
theme(axis.text.x = element_text(angle = 90))
print(p1)
print(p2)
}
}
plot_dmrs(dmr_cross, prs_annot, prs_mat,mvalues, rev(c("gray80", "gray40")))




















plot_dmrs(dmr_males,prs_annot_male,prs_mat_male, mvalues_male,rev(c("light blue", "lightblue4")))


















plot_dmrs(dmr_female, prs_annot_female, prs_mat_female, mvalues_female,rev(c("lightpink", "lightpink4")))








dmr_cross
dmr_males
dmr_female
NA
LS0tCnRpdGxlOiAiUFJTaWNlMiBEZXZlbG9wbWVudCBvZiByaXNrIHNjb3JlIgpvdXRwdXQ6IAogIGh0bWxfbm90ZWJvb2s6IAogICAgdG9jOiB5ZXMKLS0tCgpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0KbGlicmFyeSh0aWR5dmVyc2UpCmxpYnJhcnkoZ2dyZXBlbCkKbGlicmFyeShkYXRhLnRhYmxlKQpsaWJyYXJ5KGtuaXRyKQpsaWJyYXJ5KGxpbW1hKQpsaWJyYXJ5KGZvcmVhY2gpCmxpYnJhcnkoZG9QYXJhbGxlbCkKU3lzLnNldGxvY2FsZSgiTENfTUVTU0FHRVMiLCAiZW5fVVMudXRmOCIpCmtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvID0gVFJVRSkKYGBgCgojIFN0ZXAgMDogUHJlcGFyZSBjb3ZhcmlhdGVzIGFuZCBpbnB1dCBmaWxlcwpgYGB7cn0KI0BUT0RPIGNoYW5nZSB0byBjb21wdXRlIFBDcyBvbiBtdmFsdWVzCgpJRHMgPC0gZnJlYWQoIn4vZ2Vub3R5cGVfcWMvVEVSUkVfUUMvYWxsX2ltcHV0ZWRfcjJfMzBfcnNpZF9oYXJkX2NhbGwuZmFtIilbLCAuKEZJRCA9IFYxLCBJSUQgPSBWMildCnByc2ljZV9jb3YgPC0gZnJlYWQoInByc2ljZV9jb3ZfYW5kX3N0YXR1c19tdmFsdWVzLnR4dCIpCnByc2ljZV9jb3YgPC0gcHJzaWNlX2NvdlttYXRjaChJRHMkSUlELHByc2ljZV9jb3YkSUlEKV0KYWxsKElEcyRJSUQgPT1wcnNpY2VfY292JElJRCkKY292YXJpYXRlIDwtIGNiaW5kKElEcywgcHJzaWNlX2NvdlssLWMoMTYsMTcsMTgpXSkKClBEIDwtIGNiaW5kKElEcyxwcnNpY2VfY292WywxNl0pCgpoZWFkKGNvdmFyaWF0ZSkKaGVhZChQRCkKZndyaXRlKFBELCAiVEVSUkUucGhlbm8iLCBzZXAgPSAiXHQiKQpmd3JpdGUoY292YXJpYXRlLCAiVEVSUkUuY292YXJpYXRlIiwgc2VwID0gIlx0IikKYGBgCmBgYHtyfQpjb3ZhcmlhdGUKYGBgCgoKIyBTdGVwIDE6IFJ1biBQUlNpY2UtMiBvbiBOYWxscyBldCBhbCAyMDE5IFN1bXN0YXRzCmBgYHtiYXNoLGV2YWw9RkFMU0V9ClJzY3JpcHQgL2hvbWUxL05FVVJPL2Nhc2F6emEvUFJTaWNlLlIgXAogICAgLS1wcnNpY2UgL2hvbWUxL05FVVJPL2Nhc2F6emEvUFJTaWNlX2xpbnV4XAogICAgLS1iYXNlIC9ob21lMS9ORVVSTy9jYXNhenphL25hbGxzX1BELlFDLmd6XAogICAgLS1iYXNlLWluZm8gSU5GTzowLjggXAogICAgLS1iYXNlLW1hZiBNQUY6MC4wMSBcCiAgICAtLWNvdiBURVJSRS5jb3ZhcmlhdGUgXAogICAgLS1iaW5hcnktdGFyZ2V0IFRcCiAgICAtLWJldGEgIFwKICAgIC0tbGQgL2hvbWUxL05FVVJPL2Nhc2F6emEvMTAwMEdfcGxpbmsvRVVSX3BoYXNlMyAgXAogICAgLS1vdXQgVEVSUkVfUFJTaWNlIFwKICAgIC1xIDVcCiAgICAtLWFsbC1zY29yZVwKICAgIC0tcGhlbm8gVEVSUkUucGhlbm8gXAogICAgLS1zbnAgU05QIFwKICAgIC0tc3RhdCBiIFwKICAgIC0tcHZhbHVlIHBcCiAgICAtLXRhcmdldCAvaG9tZTEvTkVVUk8vY2FzYXp6YS9nZW5vdHlwZV9xYy9URVJSRV9RQy9hbGxfaW1wdXRlZF9yMl8zMF9yc2lkX2hhcmRfY2FsbCBcCiAgICAtLXRocmVhZCAzMgpgYGAKIyBTdGVwIDI6IEV2YWx1YXRlIG91dHB1dApgYGB7ciwgb3V0LndpZHRoPSI0MDBweCJ9CmluY2x1ZGVfZ3JhcGhpY3MoInByc2ljZV9pbWFnZXMvVEVSUkVfUFJTaWNlX0JBUlBMT1RfMjAyMi0wNi0zMC5wbmciKQppbmNsdWRlX2dyYXBoaWNzKCJwcnNpY2VfaW1hZ2VzL1RFUlJFX1BSU2ljZV9ISUdILVJFU19QTE9UXzIwMjItMDYtMzAucG5nIikKaW5jbHVkZV9ncmFwaGljcygicHJzaWNlX2ltYWdlcy9URVJSRV9QUlNpY2VfUVVBTlRJTEVTX1BMT1RfMjAyMi0wNi0zMC5wbmciKQoKaW5jbHVkZV9ncmFwaGljcygicHJzaWNlX2ltYWdlcy9URVJSRV9QUlNpY2VfbmFsbHNfbWFsZV9CQVJQTE9UXzIwMjItMDYtMzAucG5nIikKaW5jbHVkZV9ncmFwaGljcygicHJzaWNlX2ltYWdlcy9URVJSRV9QUlNpY2VfbmFsbHNfbWFsZV9ISUdILVJFU19QTE9UXzIwMjItMDYtMzAucG5nIikKaW5jbHVkZV9ncmFwaGljcygicHJzaWNlX2ltYWdlcy9URVJSRV9QUlNpY2VfbmFsbHNfbWFsZV9RVUFOVElMRVNfUExPVF8yMDIyLTA2LTMwLnBuZyIpCgppbmNsdWRlX2dyYXBoaWNzKCJwcnNpY2VfaW1hZ2VzL1RFUlJFX1BSU2ljZV9uYWxsc19mZW1hbGVfQkFSUExPVF8yMDIyLTA2LTMwLnBuZyIpCmluY2x1ZGVfZ3JhcGhpY3MoInByc2ljZV9pbWFnZXMvVEVSUkVfUFJTaWNlX25hbGxzX2ZlbWFsZV9ISUdILVJFU19QTE9UXzIwMjItMDYtMzAucG5nIikKaW5jbHVkZV9ncmFwaGljcygicHJzaWNlX2ltYWdlcy9URVJSRV9QUlNpY2VfbmFsbHNfZmVtYWxlX1FVQU5USUxFU19QTE9UXzIwMjItMDYtMzAucG5nIikKYGBgCiMjIFBsb3R0aW5nIFBSU2ljZSBEYXRhIG9uIG15IG93bgpgYGB7cn0KbGlicmFyeShnZ25ld3NjYWxlKQpwcnNpY2VfbWFsZV9tZXRhIDwtIGZyZWFkKCJwcnNpY2VfbmFsbHNfbWFsZV9kYXRhL1RFUlJFX1BSU2ljZV9uYWxsc19tYWxlLnByc2ljZSIpCmdncGxvdChwcnNpY2VfbWFsZV9tZXRhW1RocmVzaG9sZCA8PSAwLjVdLCBhZXMoVGhyZXNob2xkLCBOdW1fU05QLCBjb2xvciA9IC1sb2cxMChQKSkpICsKICBnZW9tX3BvaW50KCkgKwogIHNjYWxlX3lfY29udGludW91cyhicmVha3MgPSBjKHNlcSgwLCAxZTUsIDIuNWU0KSwgc2VxKDJlNSwgNmU1LCAxZTUpKSkgKwogIHRoZW1lX21pbmltYWwoKQoKcHJzaWNlX2ZlbWFsZV9tZXRhIDwtIGZyZWFkKCJwcnNpY2VfbmFsbHNfZmVtYWxlX2RhdGEvVEVSUkVfUFJTaWNlX25hbGxzX2ZlbWFsZS5wcnNpY2UiKQpnZ3Bsb3QocHJzaWNlX2ZlbWFsZV9tZXRhW1RocmVzaG9sZCA8PSAwLjVdLCBhZXMoVGhyZXNob2xkLCBOdW1fU05QLCBjb2xvciA9IC1sb2cxMChQKSkpICsKICBnZW9tX3BvaW50KCkgKwogIHNjYWxlX3lfY29udGludW91cyhicmVha3MgPSBjKHNlcSgwLCAxZTUsIDIuNWU0KSwgc2VxKDJlNSwgNmU1LCAxZTUpKSkgKwogIHRoZW1lX21pbmltYWwoKQoKcHJzaWNlX21ldGEgPC0gZnJlYWQoInByc2ljZV9kYXRhL1RFUlJFX1BSU2ljZS5wcnNpY2UiKQpnZ3Bsb3QobWFwcGluZyA9IGFlcyhUaHJlc2hvbGQsIFIyLCBjb2xvciA9IC1sb2cxMChQKSkpICsKICBnZW9tX3BvaW50KGRhdGEgPSBwcnNpY2VfZmVtYWxlX21ldGEsIHNpemUgPSAxKSArCiAgc2NhbGVfY29sb3JfZ3JhZGllbnQobG93ID0gImxpZ2h0cGluazQiLCBoaWdoID0gImxpZ2h0cGluayIpICsKICBsYWJzKGNvbG9yID0gYnF1b3RlKCJGZW1hbGUgbG9nIlsiMTAiXSB+ICIoUCkiKSkgKwogIG5ld19zY2FsZV9jb2xvcigpICsKICBnZW9tX3BvaW50KGRhdGEgPSBwcnNpY2VfbWFsZV9tZXRhLCBzaXplID0gMSwgYWVzKGNvbG9yID0gLWxvZzEwKFApKSkgKwogIHNjYWxlX2NvbG9yX2dyYWRpZW50KGxvdyA9ICJsaWdodGJsdWU0IiwgaGlnaCA9ICJsaWdodGJsdWUiKSArCiAgbGFicyh5ID0gYnF1b3RlKCJSIl4yKSwgeCA9ICJHV0FTIFAtVmFsdWUgVGhyZXNob2xkIiwgY29sb3IgPSBicXVvdGUoIk1hbGUgbG9nIlsiMTAiXSB+ICIoUCkiKSkgKwogIHRoZW1lX21pbmltYWwoKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gInRvcCIpCmdncGxvdChtYXBwaW5nID0gYWVzKFRocmVzaG9sZCwgUjIsIGNvbG9yID0gLWxvZzEwKFApKSkgKwogIGdlb21fcG9pbnQoZGF0YSA9IHByc2ljZV9mZW1hbGVfbWV0YSwgc2l6ZSA9IDEpICsKICBzY2FsZV9jb2xvcl9ncmFkaWVudChsb3cgPSAibGlnaHRwaW5rNCIsIGhpZ2ggPSAibGlnaHRwaW5rIikgKwogIGxhYnMoY29sb3IgPSBicXVvdGUoIkZlbWFsZSBsb2ciWyIxMCJdIH4gIihQKSIpKSArCiAgbmV3X3NjYWxlX2NvbG9yKCkgKwogIGdlb21fcG9pbnQoZGF0YSA9IHByc2ljZV9tYWxlX21ldGEsIHNpemUgPSAxLCBhZXMoY29sb3IgPSAtbG9nMTAoUCkpKSArCiAgc2NhbGVfY29sb3JfZ3JhZGllbnQobG93ID0gImxpZ2h0Ymx1ZTQiLCBoaWdoID0gImxpZ2h0Ymx1ZSIpICsKICBsYWJzKGNvbG9yID0gYnF1b3RlKCJNYWxlIGxvZyJbIjEwIl0gfiAiKFApIikpICsKICBuZXdfc2NhbGVfY29sb3IoKSArCiAgZ2VvbV9wb2ludChkYXRhID0gcHJzaWNlX21ldGEsIHNpemUgPSAxLCBhZXMoY29sb3IgPSAtbG9nMTAoUCkpKSArCiAgc2NhbGVfY29sb3JfZ3JhZGllbnQobG93ID0gImdyYXk0MCIsIGhpZ2ggPSAiZ3JheTgwIikgKwogIGxhYnMoeSA9IGJxdW90ZSgiUiJeMiksIHggPSAiR1dBUyBQLVZhbHVlIFRocmVzaG9sZCIsIGNvbG9yID0gYnF1b3RlKCJDcm9zcy1zZXggLWxvZyJbIjEwIl0gfiAiKFApIikpICsKICB0aGVtZV9taW5pbWFsKCkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiKQpgYGAKCiMgU3RlcCAzIHJ1biBsaW5lYXIgbW9kZWwgYXQgZGlmZmVyZW50IHRocmVzaG9sZHMgZm9yIFNOUCBpbmNsdXNpb24KYGBge3J9CmxvYWQoIi9ob21lMS9ORVVSTy9TSEFSRV9ERUNJUEhFUi9wcm9jZXNzZWRfRE5BbV9kYXRhL1RFUlJFX3Byb2Nlc3NlZF8yMDIxL2JldGFzX2NvbWJhdC5SRGF0YSIpICMgYmV0YXNfc3ViCiMgQXNzaWduIGdlbm90eXBpbmcgSUQgdG8gZGF0YQpvcmlnaW5hbF9jb3ZhcnMgPC0gZnJlYWQoIi9ob21lMS9ORVVSTy9TSEFSRV9ERUNJUEhFUi90ZXJyZV9tZXRhX21hc3Rlci5jc3YiKVssIC4ocGF0aWVudCwgSUlEID0gZ3N1YigiX1BBRS4qIiwgIiIsIElJRCkpXQpjb2xuYW1lcyhiZXRhc19jb21iYXQpIDwtIG9yaWdpbmFsX2NvdmFycyRJSURbbWF0Y2goY29sbmFtZXMoYmV0YXNfY29tYmF0KSwgb3JpZ2luYWxfY292YXJzJHBhdGllbnQpXQpiZXRhc19jb21iYXQgPC0gYmV0YXNfY29tYmF0WywgY29sbmFtZXMoYmV0YXNfY29tYmF0KSAlaW4lIGNvdmFyaWF0ZSRJSURdCmBgYApMZXQncyBjaGVjayBob3cgdGhlIGRhdGEgbG9va3MgZm9yIHRoZSBmaXJzdCA1IHN1YmplY3RzOgpgYGB7cn0KZ2dwbG90KGJldGFzX2NvbWJhdFssIDE6NV0gJT4lIGFzLmRhdGEudGFibGUoa2VlcC5yb3duYW1lcyA9IFQpICU+JSBtZWx0KGlkLnZhcnMgPSAicm4iLCB2YWx1ZS5uYW1lID0gImJldGFzIiwgdmFyaWFibGUubmFtZSA9ICJzdWJqZWN0IiksIGFlcyhiZXRhcywgY29sb3IgPSBzdWJqZWN0KSkgKwogIGdlb21fZGVuc2l0eSgpCmBgYAoKIyMjIE1hdGNoIEROQSwgUFJTLCBhbmQgbWV0YWRhdGEKYGBge3J9CnByc2ljZV9hbGwgPC0gZnJlYWQoInByc2ljZV9kYXRhL1RFUlJFX1BSU2ljZS5hbGxfc2NvcmUiKVttYXRjaChjb2xuYW1lcyhiZXRhc19jb21iYXQpLCBJSUQpLCAuKEZJRCwgSUlELCBgUHRfMC4wMjE5MDAxYCwgYFB0XzVlLTA4YCwgYFB0XzUuMDA1ZS0wNWAsIGBQdF8wLjAwMDEwMDA1YCwgYFB0XzAuMDAxMDAwMDVgLCBgUHRfMC4wMTAxNTAxYCwgYFB0XzAuMWAsIGBQdF8wLjJgLCBgUHRfMC4zYCwgYFB0XzAuNGAsIGBQdF8wLjVgLCBgUHRfMWApXQpjb3ZhcmlhdGUgPC0gY292YXJpYXRlW21hdGNoKGNvbG5hbWVzKGJldGFzX2NvbWJhdCksIElJRCldCmFsbChjb3ZhcmlhdGUkSUlEID09IGNvbG5hbWVzKGJldGFzX2NvbWJhdCkpCmFsbChjb3ZhcmlhdGUkSUlEID09IHByc2ljZV9hbGwkSUlEKQoKY292YXJpYXRlX21hbGUgPC0gY292YXJpYXRlW3NleCA9PSAxXSAlPiUgc2VsZWN0KC1zZXgpCmJldGFzX21hbGUgPC0gYmV0YXNfY29tYmF0WywgY292YXJpYXRlX21hbGUkSUlEXQpwcnNpY2VfbWFsZV9hbGwgPC0gcHJzaWNlX2FsbFttYXRjaChjb2xuYW1lcyhiZXRhc19tYWxlKSwgSUlEKSwgLihGSUQsIElJRCwgYFB0XzAuMDIxOTAwMWAsIGBQdF81ZS0wOGAsIGBQdF81LjAwNWUtMDVgLCBgUHRfMC4wMDAxMDAwNWAsIGBQdF8wLjAwMTAwMDA1YCwgYFB0XzAuMDEwMTUwMWAsIGBQdF8wLjFgLCBgUHRfMC4yYCwgYFB0XzAuM2AsIGBQdF8wLjRgLCBgUHRfMC41YCwgYFB0XzFgKV0KY292YXJpYXRlX21hbGUgPC0gY292YXJpYXRlX21hbGVbbWF0Y2goY29sbmFtZXMoYmV0YXNfbWFsZSksIElJRCldCmFsbChjb3ZhcmlhdGVfbWFsZSRJSUQgPT0gY29sbmFtZXMoYmV0YXNfbWFsZSkpCmFsbChjb3ZhcmlhdGVfbWFsZSRJSUQgPT0gcHJzaWNlX21hbGVfYWxsJElJRCkKCmNvdmFyaWF0ZV9mZW1hbGUgPC0gY292YXJpYXRlW3NleCA9PSAwXSAlPiUgc2VsZWN0KC1zZXgpCmJldGFzX2ZlbWFsZSA8LSBiZXRhc19jb21iYXRbLCBjb3ZhcmlhdGVfZmVtYWxlJElJRF0KcHJzaWNlX2ZlbWFsZV9hbGwgPC0gcHJzaWNlX2FsbFttYXRjaChjb2xuYW1lcyhiZXRhc19mZW1hbGUpLCBJSUQpLCAuKEZJRCwgSUlELCBgUHRfMC4wMjE5MDAxYCwgYFB0XzVlLTA4YCwgYFB0XzUuMDA1ZS0wNWAsIGBQdF8wLjAwMDEwMDA1YCwgYFB0XzAuMDAxMDAwMDVgLCBgUHRfMC4wMTAxNTAxYCwgYFB0XzAuMWAsIGBQdF8wLjJgLCBgUHRfMC4zYCwgYFB0XzAuNGAsIGBQdF8wLjVgLCBgUHRfMWApXQpjb3ZhcmlhdGVfZmVtYWxlIDwtIGNvdmFyaWF0ZV9mZW1hbGVbbWF0Y2goY29sbmFtZXMoYmV0YXNfZmVtYWxlKSwgSUlEKV0KYWxsKGNvdmFyaWF0ZV9mZW1hbGUkSUlEID09IGNvbG5hbWVzKGJldGFzX2ZlbWFsZSkpCmFsbChjb3ZhcmlhdGVfZmVtYWxlJElJRCA9PSBwcnNpY2VfZmVtYWxlX2FsbCRJSUQpCgoKY292YXJpYXRlX21hbGUgPC0gY292YXJpYXRlW3NleCA9PSAxXSAlPiUgc2VsZWN0KC1zZXgpCmJldGFzX21hbGUgPC0gYmV0YXNfY29tYmF0WywgY292YXJpYXRlX21hbGUkSUlEXQpwcnNpY2VfbWFsZV9uYWxsc19hbGwgPC0gZnJlYWQoInByc2ljZV9uYWxsc19tYWxlX2RhdGEvVEVSUkVfUFJTaWNlX25hbGxzX21hbGUuYWxsX3Njb3JlIilbbWF0Y2goY29sbmFtZXMoYmV0YXNfbWFsZSksIElJRCksIC4oRklELCBJSUQsIGBQdF8wLjAyMTkwMDFgLCBgUHRfNWUtMDhgLCBgUHRfNS4wMDVlLTA1YCwgYFB0XzAuMDAwMTAwMDVgLCBgUHRfMC4wMDEwMDAwNWAsIGBQdF8wLjAxMDE1MDFgLCBgUHRfMC4xYCwgYFB0XzAuMmAsIGBQdF8wLjNgLCBgUHRfMC40YCwgYFB0XzAuNWAsIGBQdF8xYCldCmNvdmFyaWF0ZV9tYWxlIDwtIGNvdmFyaWF0ZV9tYWxlW21hdGNoKGNvbG5hbWVzKGJldGFzX21hbGUpLCBJSUQpXQphbGwoY292YXJpYXRlX21hbGUkSUlEID09IGNvbG5hbWVzKGJldGFzX21hbGUpKQphbGwoY292YXJpYXRlX21hbGUkSUlEID09IHByc2ljZV9tYWxlX25hbGxzX2FsbCRJSUQpCgpjb3ZhcmlhdGVfZmVtYWxlIDwtIGNvdmFyaWF0ZVtzZXggPT0gMF0gJT4lIHNlbGVjdCgtc2V4KQpiZXRhc19mZW1hbGUgPC0gYmV0YXNfY29tYmF0WywgY292YXJpYXRlX2ZlbWFsZSRJSURdCnByc2ljZV9mZW1hbGVfbmFsbHNfYWxsIDwtIGZyZWFkKCJwcnNpY2VfbmFsbHNfZmVtYWxlX2RhdGEvVEVSUkVfUFJTaWNlX25hbGxzX2ZlbWFsZS5hbGxfc2NvcmUiKVttYXRjaChjb2xuYW1lcyhiZXRhc19mZW1hbGUpLCBJSUQpLCAuKEZJRCwgSUlELCBgUHRfMC4wMjE5MDAxYCwgYFB0XzVlLTA4YCwgYFB0XzUuMDA1ZS0wNWAsIGBQdF8wLjAwMDEwMDA1YCwgYFB0XzAuMDAxMDAwMDVgLCBgUHRfMC4wMTAxNTAxYCwgYFB0XzAuMWAsIGBQdF8wLjJgLCBgUHRfMC4zYCwgYFB0XzAuNGAsIGBQdF8wLjVgLCBgUHRfMWApXQpjb3ZhcmlhdGVfZmVtYWxlIDwtIGNvdmFyaWF0ZV9mZW1hbGVbbWF0Y2goY29sbmFtZXMoYmV0YXNfZmVtYWxlKSwgSUlEKV0KYWxsKGNvdmFyaWF0ZV9mZW1hbGUkSUlEID09IGNvbG5hbWVzKGJldGFzX2ZlbWFsZSkpCmFsbChjb3ZhcmlhdGVfZmVtYWxlJElJRCA9PSBwcnNpY2VfZmVtYWxlX25hbGxzX2FsbCRJSUQpCmBgYAojIyMgUnVuIGxpbW1hCgpgYGB7cn0KbXZhbHVlcyA8LSBsdW1pOjpiZXRhMm0oYmV0YXNfY29tYmF0KQpwcnNfbWF0IDwtIHByc2ljZV9hbGxbLCAtYygxLCAyKV0KY292X21hdCA8LSBjb3ZhcmlhdGVbLCAtYygxLCAyKV0KCm12YWx1ZXNfbWFsZSA8LSBsdW1pOjpiZXRhMm0oYmV0YXNfbWFsZSkKcHJzX21hdF9tYWxlIDwtIHByc2ljZV9tYWxlX2FsbFssIC1jKDEsIDIpXQpjb3ZfbWF0X21hbGUgPC0gY292YXJpYXRlX21hbGVbLCAtYygxLCAyKV0KCm12YWx1ZXNfZmVtYWxlIDwtIGx1bWk6OmJldGEybShiZXRhc19mZW1hbGUpCnByc19tYXRfZmVtYWxlIDwtIHByc2ljZV9mZW1hbGVfYWxsWywgLWMoMSwgMildCmNvdl9tYXRfZmVtYWxlIDwtIGNvdmFyaWF0ZV9mZW1hbGVbLCAtYygxLCAyKV0KCnByc19tYXRfbmFsbHNfbWFsZSA8LSBwcnNpY2VfbWFsZV9uYWxsc19hbGxbLCAtYygxLCAyKV0KcHJzX21hdF9uYWxsc19mZW1hbGUgPC0gcHJzaWNlX2ZlbWFsZV9uYWxsc19hbGxbLCAtYygxLCAyKV0KYGBgCgpgYGB7cn0KcmVnaXN0ZXJEb1BhcmFsbGVsKG5jb2wocHJzX21hdCkgLyAyKQpoaXRzIDwtIGZvcmVhY2gocHJzX3RocmVzaCA9IGNvbG5hbWVzKHByc19tYXQpKSAlZG9wYXIlIHsKICBkZXNpZ25fcHJzIDwtIG1vZGVsLm1hdHJpeCh+LiwgZGF0YSA9IGNiaW5kKHByc19tYXRbLCAuLnByc190aHJlc2hdLCBjb3ZfbWF0KSkKICBwcnNfZml0IDwtIGxtRml0KG12YWx1ZXMsIGRlc2lnbl9wcnMpCiAgcHJzX2ZpdCA8LSBlQmF5ZXMocHJzX2ZpdCkKICB0b3BUYWJsZShwcnNfZml0LCBjb2VmID0gMiwgYWRqdXN0Lm1ldGhvZCA9ICJib25mIiwgcC52YWx1ZSA9IDAuMDUsIG51bWJlciA9IEluZiwgZ2VuZWxpc3QgPSByb3duYW1lcyhtdmFsdWVzKSkKfQpuYW1lcyhoaXRzKSA8LSBjb2xuYW1lcyhwcnNfbWF0KQpoaXRzX2J5X3RocmVzaF9ib25mIDwtIHJiaW5kbGlzdChoaXRzLCBpZGNvbCA9ICJ0aHJlc2hvbGQiLCBmaWxsID0gVFJVRSkKCnJlZ2lzdGVyRG9QYXJhbGxlbChuY29sKHByc19tYXRfbWFsZSkgLyAyKQpoaXRzX21hbGUgPC0gZm9yZWFjaChwcnNfdGhyZXNoID0gY29sbmFtZXMocHJzX21hdF9tYWxlKSkgJWRvcGFyJSB7CiAgZGVzaWduX3Byc19tYWxlIDwtIG1vZGVsLm1hdHJpeCh+LiwgZGF0YSA9IGNiaW5kKHByc19tYXRfbWFsZVssIC4ucHJzX3RocmVzaF0sIGNvdl9tYXRfbWFsZSkpCiAgcHJzX2ZpdF9tYWxlIDwtIGxtRml0KG12YWx1ZXNfbWFsZSwgZGVzaWduX3Byc19tYWxlKQogIHByc19maXRfbWFsZSA8LSBlQmF5ZXMocHJzX2ZpdF9tYWxlKQogIHRvcFRhYmxlKHByc19maXRfbWFsZSwgY29lZiA9IDIsIGFkanVzdC5tZXRob2QgPSAiYm9uZiIsIHAudmFsdWUgPSAwLjA1LCBudW1iZXIgPSBJbmYsIGdlbmVsaXN0ID0gcm93bmFtZXMobXZhbHVlc19tYWxlKSkKfQpuYW1lcyhoaXRzX21hbGUpIDwtIGNvbG5hbWVzKHByc19tYXRfbWFsZSkKaGl0c19ieV90aHJlc2hfYm9uZl9tYWxlIDwtIHJiaW5kbGlzdChoaXRzX21hbGUsIGlkY29sID0gInRocmVzaG9sZCIsIGZpbGwgPSBUUlVFKQoKcmVnaXN0ZXJEb1BhcmFsbGVsKG5jb2wocHJzX21hdF9mZW1hbGUpIC8gMikKaGl0c19mZW1hbGUgPC0gZm9yZWFjaChwcnNfdGhyZXNoID0gY29sbmFtZXMocHJzX21hdF9mZW1hbGUpKSAlZG9wYXIlIHsKICBkZXNpZ25fcHJzX2ZlbWFsZSA8LSBtb2RlbC5tYXRyaXgofi4sIGRhdGEgPSBjYmluZChwcnNfbWF0X2ZlbWFsZVssIC4ucHJzX3RocmVzaF0sIGNvdl9tYXRfZmVtYWxlKSkKICBwcnNfZml0X2ZlbWFsZSA8LSBsbUZpdChtdmFsdWVzX2ZlbWFsZSwgZGVzaWduX3Byc19mZW1hbGUpCiAgcHJzX2ZpdF9mZW1hbGUgPC0gZUJheWVzKHByc19maXRfZmVtYWxlKQogIHRvcFRhYmxlKHByc19maXRfZmVtYWxlLCBjb2VmID0gMiwgYWRqdXN0Lm1ldGhvZCA9ICJib25mIiwgcC52YWx1ZSA9IDAuMDUsIG51bWJlciA9IEluZiwgZ2VuZWxpc3QgPSByb3duYW1lcyhtdmFsdWVzX2ZlbWFsZSkpCn0KbmFtZXMoaGl0c19mZW1hbGUpIDwtIGNvbG5hbWVzKHByc19tYXRfZmVtYWxlKQpoaXRzX2J5X3RocmVzaF9ib25mX2ZlbWFsZSA8LSByYmluZGxpc3QoaGl0c19mZW1hbGUsIGlkY29sID0gInRocmVzaG9sZCIsIGZpbGwgPSBUUlVFKQoKcmVnaXN0ZXJEb1BhcmFsbGVsKG5jb2wocHJzX21hdF9tYWxlKSAvIDIpCmhpdHNfbmFsbHNfbWFsZSA8LSBmb3JlYWNoKHByc190aHJlc2ggPSBjb2xuYW1lcyhwcnNfbWF0X25hbGxzX21hbGUpKSAlZG9wYXIlIHsKICBkZXNpZ25fcHJzX25hbGxzX21hbGUgPC0gbW9kZWwubWF0cml4KH4uLCBkYXRhID0gY2JpbmQocHJzX21hdF9uYWxsc19tYWxlWywgLi5wcnNfdGhyZXNoXSwgY292X21hdF9tYWxlKSkKICBwcnNfZml0X25hbGxzX21hbGUgPC0gbG1GaXQobXZhbHVlc19tYWxlLCBkZXNpZ25fcHJzX25hbGxzX21hbGUpCiAgcHJzX2ZpdF9uYWxsc19tYWxlIDwtIGVCYXllcyhwcnNfZml0X25hbGxzX21hbGUpCiAgdG9wVGFibGUocHJzX2ZpdF9uYWxsc19tYWxlLCBjb2VmID0gMiwgYWRqdXN0Lm1ldGhvZCA9ICJib25mIiwgcC52YWx1ZSA9IDAuMDUsIG51bWJlciA9IEluZiwgZ2VuZWxpc3QgPSByb3duYW1lcyhtdmFsdWVzX21hbGUpKQp9Cm5hbWVzKGhpdHNfbmFsbHNfbWFsZSkgPC0gY29sbmFtZXMocHJzX21hdF9uYWxsc19tYWxlKQpoaXRzX2J5X3RocmVzaF9ib25mX25hbGxzX21hbGUgPC0gcmJpbmRsaXN0KGhpdHNfbmFsbHNfbWFsZSwgaWRjb2wgPSAidGhyZXNob2xkIiwgZmlsbCA9IFRSVUUpCgpyZWdpc3RlckRvUGFyYWxsZWwobmNvbChwcnNfbWF0X2ZlbWFsZSkgLyAyKQpoaXRzX25hbGxzX2ZlbWFsZSA8LSBmb3JlYWNoKHByc190aHJlc2ggPSBjb2xuYW1lcyhwcnNfbWF0X25hbGxzX2ZlbWFsZSkpICVkb3BhciUgewogIGRlc2lnbl9wcnNfbmFsbHNfZmVtYWxlIDwtIG1vZGVsLm1hdHJpeCh+LiwgZGF0YSA9IGNiaW5kKHByc19tYXRfbmFsbHNfZmVtYWxlWywgLi5wcnNfdGhyZXNoXSwgY292X21hdF9mZW1hbGUpKQogIHByc19maXRfbmFsbHNfZmVtYWxlIDwtIGxtRml0KG12YWx1ZXNfZmVtYWxlLCBkZXNpZ25fcHJzX25hbGxzX2ZlbWFsZSkKICBwcnNfZml0X25hbGxzX2ZlbWFsZSA8LSBlQmF5ZXMocHJzX2ZpdF9uYWxsc19mZW1hbGUpCiAgdG9wVGFibGUocHJzX2ZpdF9uYWxsc19mZW1hbGUsIGNvZWYgPSAyLCBhZGp1c3QubWV0aG9kID0gImJvbmYiLCBwLnZhbHVlID0gMC4wNSwgbnVtYmVyID0gSW5mLCBnZW5lbGlzdCA9IHJvd25hbWVzKG12YWx1ZXNfZmVtYWxlKSkKfQpuYW1lcyhoaXRzX25hbGxzX2ZlbWFsZSkgPC0gY29sbmFtZXMocHJzX21hdF9uYWxsc19mZW1hbGUpCmhpdHNfYnlfdGhyZXNoX2JvbmZfbmFsbHNfZmVtYWxlIDwtIHJiaW5kbGlzdChoaXRzX25hbGxzX2ZlbWFsZSwgaWRjb2wgPSAidGhyZXNob2xkIiwgZmlsbCA9IFRSVUUpCmBgYAoKIyMjIFBsb3R0aW5nIEVXQVMgdnMgVGhyZXNob2xkIEV4cGVyaW1lbnQgYnkgU2V4CmBgYHtyfQp0b19wbG90IDwtIHJiaW5kKAogIGhpdHNfYnlfdGhyZXNoX2JvbmZbLCAuKGhpdHMgPSAuTiwgU2V4ID0gIkNyb3NzLXNleCIpLCBieSA9IHRocmVzaG9sZF0gJT4lCiAgICBtdXRhdGUodGhyZXNob2xkID0gcmVjb2RlX2ZhY3Rvcih0aHJlc2hvbGQsIGBQdF8wLjAyMTkwMDFgID0gIjAuMDIxOSIsIGBQdF81ZS0wOGAgPSAiNWUtOCIsIGBQdF81LjAwNWUtMDVgID0gIjVlLTUiLCBgUHRfMC4wMDAxMDAwNWAgPSAiMWUtNCIsIGBQdF8wLjAwMTAwMDA1YCA9ICIxZS0zIiwgYFB0XzAuMDEwMTUwMWAgPSAiMWUtMiIsIGBQdF8wLjFgID0gIjAuMSIsIGBQdF8wLjJgID0gIjAuMiIsIGBQdF8wLjNgID0gIjAuMyIsIGBQdF8wLjRgID0gIjAuNCIsIGBQdF8wLjVgID0gIjAuNSIsIGBQdF8xYCA9ICIxLjAiKSksCiAgaGl0c19ieV90aHJlc2hfYm9uZl9uYWxsc19tYWxlWywgLihoaXRzID0gLk4sIFNleCA9ICJNYWxlIiksIGJ5ID0gdGhyZXNob2xkXSAlPiUKICAgIG11dGF0ZSh0aHJlc2hvbGQgPSByZWNvZGVfZmFjdG9yKHRocmVzaG9sZCwgYFB0XzAuMDIxOTAwMWAgPSAiMC4wMjE5IiwgYFB0XzVlLTA4YCA9ICI1ZS04IiwgYFB0XzUuMDA1ZS0wNWAgPSAiNWUtNSIsIGBQdF8wLjAwMDEwMDA1YCA9ICIxZS00IiwgYFB0XzAuMDAxMDAwMDVgID0gIjFlLTMiLCBgUHRfMC4wMTAxNTAxYCA9ICIxZS0yIiwgYFB0XzAuMWAgPSAiMC4xIiwgYFB0XzAuMmAgPSAiMC4yIiwgYFB0XzAuM2AgPSAiMC4zIiwgYFB0XzAuNGAgPSAiMC40IiwgYFB0XzAuNWAgPSAiMC41IiwgYFB0XzFgID0gIjEuMCIpKSwKICBoaXRzX2J5X3RocmVzaF9ib25mX25hbGxzX2ZlbWFsZVssIC4oaGl0cyA9IC5OLCBTZXggPSAiRmVtYWxlIiksIGJ5ID0gdGhyZXNob2xkXSAlPiUKICAgIG11dGF0ZSh0aHJlc2hvbGQgPSByZWNvZGVfZmFjdG9yKHRocmVzaG9sZCwgYFB0XzAuMDIxOTAwMWAgPSAiMC4wMjE5IiwgYFB0XzVlLTA4YCA9ICI1ZS04IiwgYFB0XzUuMDA1ZS0wNWAgPSAiNWUtNSIsIGBQdF8wLjAwMDEwMDA1YCA9ICIxZS00IiwgYFB0XzAuMDAxMDAwMDVgID0gIjFlLTMiLCBgUHRfMC4wMTAxNTAxYCA9ICIxZS0yIiwgYFB0XzAuMWAgPSAiMC4xIiwgYFB0XzAuMmAgPSAiMC4yIiwgYFB0XzAuM2AgPSAiMC4zIiwgYFB0XzAuNGAgPSAiMC40IiwgYFB0XzAuNWAgPSAiMC41IiwgYFB0XzFgID0gIjEuMCIpKQopICU+JSBtdXRhdGUoU2V4ID0gZmFjdG9yKFNleCwgbGV2ZWxzID0gYygiQ3Jvc3Mtc2V4IiwgIk1hbGUiLCAiRmVtYWxlIikpKQpwbG90X3BvcyA8LSBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDEpCmdncGxvdCh0b19wbG90LCBhZXModGhyZXNob2xkLCBoaXRzLCBmaWxsID0gU2V4LCBsYWJlbCA9IGhpdHMpKSArCiAgZ2VvbV90ZXh0KHBvc2l0aW9uID0gcGxvdF9wb3MsIHZqdXN0ID0gLTAuMjUpICsKICBnZW9tX2NvbChwb3NpdGlvbiA9IHBsb3RfcG9zKSArCiAgbGFicyh4ID0gIkdXQVMgUCBWYWx1ZSBUaHJlc2hvbGQiLCB5ID0gIkVXQVMgSGl0cyIpICsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCJncmV5ODAiLCAibGlnaHRibHVlIiwgImxpZ2h0cGluayIpKSArCiAgdGhlbWVfbWluaW1hbCgpCmhpdHNfYnlfdGhyZXNoX2JvbmZbLCAuKGhpdHMgPSAuTiwgU2V4ID0gIkNyb3NzLXNleCIpLCBieSA9IHRocmVzaG9sZF0KaGl0c19ieV90aHJlc2hfYm9uZl9uYWxsc19tYWxlWywgLihoaXRzID0gLk4pLCBieSA9IHRocmVzaG9sZF0KaGl0c19ieV90aHJlc2hfYm9uZl9uYWxsc19mZW1hbGVbLCAuKGhpdHMgPSAuTiksIGJ5ID0gdGhyZXNob2xkXQpgYGAKYGBge3J9CmRpc3BsYXlfdmVubiA8LSBmdW5jdGlvbih4LCAuLi4pIHsKICBsaWJyYXJ5KFZlbm5EaWFncmFtKQogIGdyaWQubmV3cGFnZSgpCiAgdmVubl9vYmplY3QgPC0gdmVubi5kaWFncmFtKHgsIGZpbGVuYW1lID0gTlVMTCwgLi4uKQogIGdyaWQuZHJhdyh2ZW5uX29iamVjdCkKfQoKZGlzcGxheV92ZW5uKGxpc3QoYENyb3NzLXNleGAgPSBoaXRzX2J5X3RocmVzaF9ib25mW3RocmVzaG9sZCA9PSAiUHRfNWUtMDgiXSRJRCwgTWFsZSA9IGhpdHNfYnlfdGhyZXNoX2JvbmZfbmFsbHNfbWFsZVt0aHJlc2hvbGQgPT0gIlB0XzVlLTA4Il0kSUQsIEZlbWFsZSA9IGhpdHNfYnlfdGhyZXNoX2JvbmZfbmFsbHNfZmVtYWxlW3RocmVzaG9sZCA9PSAiUHRfNWUtMDgiXSRJRCksIGZpbGwgPSBjKCJncmF5ODAiLCAibGlnaHRibHVlIiwgImxpZ2h0cGluayIpKQptYWxlX2lkcyA8LSBoaXRzX2J5X3RocmVzaF9ib25mX25hbGxzX21hbGVbdGhyZXNob2xkID09ICJQdF81ZS0wOCJdJElECmNyb3NzX2lkcyA8LSBoaXRzX2J5X3RocmVzaF9ib25mW3RocmVzaG9sZCA9PSAiUHRfNWUtMDgiXSRJRAptYWxlX2lkc1shbWFsZV9pZHMgJWluJSBjcm9zc19pZHNdCmBgYAoKYGBge3IsZXZhbD1GQUxTRX0KbGlicmFyeShtaXNzTWV0aHlsKQpnb21ldGgoaGl0c19ieV90aHJlc2hfYm9uZlt0aHJlc2hvbGQgPT0gIlB0XzVlLTA4Il0kSUQsIGFycmF5LnR5cGUgPSAiRVBJQyIsIGFsbC5jcGcgPSByb3duYW1lcyhtdmFsdWVzKSkKYGBgCgpgYGB7cn0KZ2V0X2Z1bGxfZml0IDwtIGZ1bmN0aW9uKHByc19tYXQsY292X21hdCxtdmFsdWVzKXsKICB0b3BfZGVzaWduX3BycyA8LSBtb2RlbC5tYXRyaXgofi4sIGRhdGEgPSBjYmluZChwcnNfbWF0WywgYFB0XzVlLTA4YF0sIGNvdl9tYXQpKQogIHRvcF9wcnNfZml0IDwtIGxtRml0KG12YWx1ZXMsIHRvcF9kZXNpZ25fcHJzKQogIHRvcF9wcnNfZml0IDwtIGVCYXllcyh0b3BfcHJzX2ZpdCkKICB0b3BfcHJzX2hpdHMgPC0gdG9wVGFibGUodG9wX3Byc19maXQsIGNvZWYgPSAyLCBhZGp1c3QubWV0aG9kID0gImJvbmYiLCBudW1iZXIgPSBJbmYsIGdlbmVsaXN0ID0gcm93bmFtZXMobXZhbHVlcykpCn0KdG9wX3Byc19oaXRzIDwtIGdldF9mdWxsX2ZpdChwcnNfbWF0LGNvdl9tYXQsbXZhbHVlcykKdG9wX21hbGVfcHJzX2hpdHMgPC0gZ2V0X2Z1bGxfZml0KHByc19tYXRfbmFsbHNfbWFsZSwgY292X21hdF9tYWxlLCBtdmFsdWVzX21hbGUpCnRvcF9mZW1hbGVfcHJzX2hpdHMgPC0gZ2V0X2Z1bGxfZml0KHByc19tYXRfbmFsbHNfZmVtYWxlLCBjb3ZfbWF0X2ZlbWFsZSwgbXZhbHVlc19mZW1hbGUpCmBgYApgYGB7cn0KbWFuaWZlc3QgPC0gSWxsdW1pbmFIdW1hbk1ldGh5bGF0aW9uRVBJQ2Fubm8uaWxtMTBiNC5oZzE5OjpPdGhlciAlPiUKICBhcy5kYXRhLmZyYW1lKCkgJT4lCiAgcm93bmFtZXNfdG9fY29sdW1uKHZhciA9ICJuYW1lIikKcHJzX2Fubm90IDwtIGRhdGEudGFibGUodG9wX3Byc19oaXRzKVttYW5pZmVzdCwgZ2VuZSA6PSBnc3ViKCI7LioiLCAiIiwgVUNTQ19SZWZHZW5lX05hbWUpLCBvbiA9IGMoSUQgPSAibmFtZSIpXQpwcnNfYW5ub3RfbWFsZSA8LSBkYXRhLnRhYmxlKHRvcF9tYWxlX3Byc19oaXRzKVttYW5pZmVzdCwgZ2VuZSA6PSBnc3ViKCI7LioiLCAiIiwgVUNTQ19SZWZHZW5lX05hbWUpLCBvbiA9IGMoSUQgPSAibmFtZSIpXQpwcnNfYW5ub3RfZmVtYWxlPC0gZGF0YS50YWJsZSh0b3BfZmVtYWxlX3Byc19oaXRzKVttYW5pZmVzdCwgZ2VuZSA6PSBnc3ViKCI7LioiLCAiIiwgVUNTQ19SZWZHZW5lX05hbWUpLCBvbiA9IGMoSUQgPSAibmFtZSIpXQpwbG90X3Byc19oaXRzIDwtIGZ1bmN0aW9uKHByc19hbm5vdCxsYWJlbF9jb2xvcil7CiAgZ2dwbG90KHByc19hbm5vdCwgYWVzKGxvZ0ZDLCAtbG9nMTAoUC5WYWx1ZSkpKSArCiAgICBnZW9tX3BvaW50KCkgKwogICAgZ2VvbV9wb2ludCgKICAgICAgZGF0YSA9IHN1YnNldChwcnNfYW5ub3QsIGFkai5QLlZhbCA8IDAuMDUgJiBhYnMobG9nRkMpID4gMC4wMyksCiAgICAgIGNvbG9yID0gbGFiZWxfY29sb3IsCiAgICAgIG1hcHBpbmcgPSBhZXMobG9nRkMsIC1sb2cxMChQLlZhbHVlKSkKICAgICkgKwogICAgZ2VvbV9obGluZSgKICAgICAgbGluZXR5cGUgPSAiZGFzaGVkIiwKICAgICAgeWludGVyY2VwdCA9IG1pbigtbG9nMTAocHJzX2Fubm90JFAuVmFsdWVbcHJzX2Fubm90JGFkai5QLlZhbCA8IDAuMDVdKSkKICAgICkgKwogICAgZ2VvbV92bGluZShsaW5ldHlwZSA9ICJkYXNoZWQiLCB4aW50ZXJjZXB0ID0gMC4wMykgKwogICAgZ2VvbV92bGluZShsaW5ldHlwZSA9ICJkYXNoZWQiLCB4aW50ZXJjZXB0ID0gLTAuMDMpICsKICAgIGdlb21fdGV4dF9yZXBlbCgKICAgICAgZGF0YSA9IHByc19hbm5vdCAlPiUgZmlsdGVyKGFicyhsb2dGQykgPiAwLjAzICYgYWRqLlAuVmFsIDwgMC4wNSksCiAgICAgIGNvbG9yID0gImRvZGdlcmJsdWUiLAogICAgICBtYXBwaW5nID0gYWVzKGxvZ0ZDLCAtbG9nMTAoUC5WYWx1ZSksIGxhYmVsID0gaWZlbHNlKGdlbmUgIT0gIiIsIGdlbmUsIElEKSksCiAgICAgIHNpemUgPSAzLAogICAgICBtYXgub3ZlcmxhcHMgPSAyMAogICAgKSArCiAgICBsYWJzKHkgPSBicXVvdGUoImxvZyJbMTBdIH4gIihQKSIpLCB4ID0gcXVvdGUoRGVsdGEgfiAiTSIgfiBNZXRoeWxhdGlvbikpICsKICAgIHRoZW1lX21pbmltYWwoKQp9CgpwbG90X3Byc19oaXRzKHByc19hbm5vdCwiZ3JheTQwIikKcGxvdF9wcnNfaGl0cyhwcnNfYW5ub3RfbWFsZSwibGlnaHRibHVlIikKcGxvdF9wcnNfaGl0cyhwcnNfYW5ub3RfZmVtYWxlLCJwaW5rIikKYGBgCmBgYHtyfQptYW5pZmVzdFttYW5pZmVzdCRuYW1lID09ImNnMDY4NDYyODIiLF0KYGBgCgojIE1hbmhhdHRhbiBwbG90IHZzIEdXQVMgbWFuaGF0dGFuIHBsb3QKYGBge3IsZXZhbD1GQUxTRX0KbGlicmFyeShxcW1hbikKY3BnX3BvcyA8LSBJbGx1bWluYUh1bWFuTWV0aHlsYXRpb25FUElDYW5uby5pbG0xMGI0LmhnMTk6OkxvY2F0aW9ucyAlPiUKICBhcy5kYXRhLmZyYW1lKCkgJT4lCiAgcm93bmFtZXNfdG9fY29sdW1uKHZhciA9ICJuYW1lIikKY29weV9hbm5vdCA8LSBwcnNfYW5ub3RbY3BnX3Bvcywgb24gPSBjKElEID0gIm5hbWUiKV0gJT4lCiAgbXV0YXRlKGNociA9IGFzLm51bWVyaWMocmVjb2RlKGdzdWIoImNociIsICIiLCBjaHIpLFg9IjIzIixZPSIyNCIpKSkKdG9fcGxvdCA8LSBjb3B5X2Fubm90WywgLihTTlAgPSBnZW5lLCBDSFIgPSBjaHIsIEJQID0gcG9zLCBQID0gUC5WYWx1ZSwgRkRSID0gYWRqLlAuVmFsKV1bIWlzLm5hKFApXQptYW5oYXR0YW4odG9fcGxvdCwKICBhbm5vdGF0ZVB2YWwgPSBtYXgodG9fcGxvdFtGRFIgPCAwLjA1XSRQKSwKICBhbm5vdGF0ZVRvcCA9IFRSVUUsCiAgZ2Vub21ld2lkZWxpbmUgPSBtaW4oLWxvZzEwKHRvX3Bsb3RbRkRSIDwgMC4wNV0kUCkpLAogIHN1Z2dlc3RpdmVsaW5lID0gRkFMU0UKKQptYW5oYXR0YW4odG9fcGxvdFtDSFIgPT0gMTddLAogIGFubm90YXRlUHZhbCA9IG1heCh0b19wbG90W0ZEUiA8IDAuMDVdJFApLAogIGFubm90YXRlVG9wID0gRkFMU0UsCiAgZ2Vub21ld2lkZWxpbmUgPSBtaW4oLWxvZzEwKHRvX3Bsb3RbRkRSIDwgMC4wNV0kUCkpLAogIHN1Z2dlc3RpdmVsaW5lID0gRkFMU0UKKQpxcSh0b19wbG90JFApCmBgYApgYGB7cixldmFsPUZBTFNFfQpHV0FTIDwtIGZyZWFkKCJ+L25hbGxzX1BELlFDLmd6IikKCm1hbmhhdHRhbihHV0FTLAogIGFubm90YXRlUHZhbCA9IDVlLTgsCiAgYnAgPSAiUE9TIiwKICBwID0gInAiLAogIHN1Z2dlc3RpdmVsaW5lID0gRkFMU0UKKQpgYGAKCgoKIyMgRE1ScwoKYGBge3J9CmxpYnJhcnkoRE1SY2F0ZSkKUzRfdG9fZGF0YWZyYW1lIDwtIGZ1bmN0aW9uKHM0b2JqKSB7CiAgbm1zIDwtIHNsb3ROYW1lcyhzNG9iaikKICBsc3QgPC0gbGFwcGx5KG5tcywgZnVuY3Rpb24obm0pIHNsb3QoczRvYmosIG5tKSkKICBhcy5kYXRhLmZyYW1lKHNldE5hbWVzKGxzdCwgbm1zKSkKfQpydW5fZG1yY2F0ZSA8LSBmdW5jdGlvbihwcnNfbWF0LGNvdl9tYXQsbXZhbHVlcyl7CiAgZGVzaWduX3BycyA8LSBtb2RlbC5tYXRyaXgofi4sIGRhdGEgPSBjYmluZChwcnNfbWF0WywgYFB0XzVlLTA4YF0sIGNvdl9tYXQpKQogIHByc19hbm5vdGF0ZWQgPC0gY3BnLmFubm90YXRlKGRhdGF0eXBlID0gImFycmF5Iiwgb2JqZWN0ID0gbXZhbHVlcywgYW5hbHlzaXMudHlwZSA9ICJkaWZmZXJlbnRpYWwiLCBkZXNpZ24gPSBkZXNpZ25fcHJzLCBjb2VmID0gMiwgd2hhdCA9ICJNIiwgYXJyYXl0eXBlID0gIkVQSUMiLCBmZHIgPSAwLjA1KQogIHByc19kbXJfcmVzIDwtIGRtcmNhdGUocHJzX2Fubm90YXRlZCwgbGFtYmRhID0gMTAwMCwgQyA9IDIpCiAgcmV0dXJuKFM0X3RvX2RhdGFmcmFtZShwcnNfZG1yX3JlcykpCn0KZG1yX2Nyb3NzIDwtIHJ1bl9kbXJjYXRlKHByc19tYXQsIGNvdl9tYXQsIG12YWx1ZXMpCmRtcl9tYWxlcyA8LSBydW5fZG1yY2F0ZShwcnNfbWF0X25hbGxzX21hbGUsY292X21hdF9tYWxlLG12YWx1ZXNfbWFsZSkKZG1yX2ZlbWFsZSA8LSBydW5fZG1yY2F0ZShwcnNfbWF0X25hbGxzX2ZlbWFsZSxjb3ZfbWF0X2ZlbWFsZSxtdmFsdWVzX2ZlbWFsZSkKYGBgCmBgYHtyfQphbm5vdGF0aW9uIDwtIG1pbmZpOjpnZXRBbm5vdGF0aW9uKElsbHVtaW5hSHVtYW5NZXRoeWxhdGlvbkVQSUNhbm5vLmlsbTEwYjQuaGcxOSkKYGBgCiMjIyBQbG90dGluZyBhbGwgRE1ScyB7LnRhYnNldCAudGFic2V0LWZhZGV9CmBgYHtyfQpnZXRfZG1yX2VmZmVjdHMgPC0gZnVuY3Rpb24oZG1yLCBsaW1tYV9yZXMsbXZhbHVlcykgewogIGRtcl9jb29yZCA8LSBzdHJfbWF0Y2hfYWxsKGFzLmNoYXJhY3RlcihkbXIpLCAiKGNoci4qKTooWzAtOV0qKS0oWzAtOV0qKSIpW1sxXV0KICBjcGdzIDwtIGFzLmRhdGEudGFibGUoYW5ub3RhdGlvblthbm5vdGF0aW9uJGNociA9PSBkbXJfY29vcmRbMl0gJiBhbm5vdGF0aW9uJHBvcyA+PSBhcy5udW1lcmljKGRtcl9jb29yZFszXSkgJiBhbm5vdGF0aW9uJHBvcyA8PSBhcy5udW1lcmljKGRtcl9jb29yZFs0XSksIF0pCiAgcmVzIDwtIGxpbW1hX3Jlc1tjcGdzLG9uPWMoIklEIj0iTmFtZSIpLG5vbWF0Y2g9MCBdCiAgZG1yXzEgPC0gYXMuZGF0YS5mcmFtZShyZXNbIWlzLm5hKHJlcyRsb2dGQyksIF0pCiAgZG1yX21ldGh5IDwtIHJlc2hhcGUyOjptZWx0KGx1bWk6Om0yYmV0YShtdmFsdWVzW2Rtcl8xJElELCBdKSwgc3RyaW5nc0FzRmFjdG9ycyA9IEZBTFNFKQogIHRvX3Bsb3QgPC0gbWVyZ2UoZG1yXzEsIGRtcl9tZXRoeSwgYnkueCA9ICJJRCIsIGJ5LnkgPSAiVmFyMSIpCiAgdG9fcGxvdCRETVIgPC0gZG1yCiAgdG9fcGxvdAp9CmdldF9kbXJfcmVzIDwtIGZ1bmN0aW9uKGRtciwgbGltbWFfcmVzKSB7CiAgZG1yX2Nvb3JkIDwtIHN0cl9tYXRjaF9hbGwoYXMuY2hhcmFjdGVyKGRtciksICIoY2hyLiopOihbMC05XSopLShbMC05XSopIilbWzFdXQogIGNwZ3MgPC0gYW5ub3RhdGlvblthbm5vdGF0aW9uJGNociA9PSBkbXJfY29vcmRbMl0gJiBhbm5vdGF0aW9uJHBvcyA+PSBhcy5udW1lcmljKGRtcl9jb29yZFszXSkgJiBhbm5vdGF0aW9uJHBvcyA8PSBhcy5udW1lcmljKGRtcl9jb29yZFs0XSksIF0KICByZXMgPC0gY2JpbmQoY3BncywgbGltbWFfcmVzW2NwZ3MkTmFtZSwgXSkKICByZXMkRE1SIDwtIGRtcgogIHJldHVybihyZXMpCn0KcGxvdF9kbXJzIDwtIGZ1bmN0aW9uKGRtcl9yZXMsbGltbWFfcmVzLHByc19tYXQsIG12YWx1ZXMsIGNhc2VfY29udHJvbCkgewogIHRvX3Bsb3QgPC0gcmJpbmRsaXN0KGxhcHBseShkbXJfcmVzJGNvb3JkLCBmdW5jdGlvbihkbXIpIGdldF9kbXJfZWZmZWN0cyhkbXIsIGxpbW1hX3JlcyxtdmFsdWVzKSkpICU+JQogICAgbXV0YXRlKFNDT1JFMV9BVkcgPSBzY2FsZShwcnNfbWF0W21hdGNoKFZhcjIsSURzJElJRCksYFB0XzVlLTA4YF0pLFBEID0gUERbbWF0Y2goVmFyMixJSUQpXSRQRCkgJT4lCiAgICBmaWx0ZXIoIWlzLm5hKFNDT1JFMV9BVkcpKQogIGZvcihjdXJfZG1yIGluIHVuaXF1ZSh0b19wbG90JERNUikpewogICAgY3VyX3Bsb3QgPC0gdG9fcGxvdFtETVIgPT0gY3VyX2Rtcl0KICAgIHAxIDwtIGdncGxvdChjdXJfcGxvdCAsIGFlcyhwb3MsIHZhbHVlLCBjb2xvciA9IFNDT1JFMV9BVkcpKSArCiAgICAgIGdlb21fcG9pbnQoKSArCiAgICAgIHNjYWxlX2NvbG9yX2dyYWRpZW50KGxvdyA9IHJldihjYXNlX2NvbnRyb2wpWzFdLCBoaWdoID0gcmV2KGNhc2VfY29udHJvbClbMl0pICsKICAgICAgdGhlbWVfbWluaW1hbCgpICsKICAgICAgbGFicyh0aXRsZSA9IHVuaXF1ZShjdXJfcGxvdCRETVIpLHg9IlBPUyIseT1icXVvdGUoIk1ldGh5bGF0aW9uIn5iZXRhKSxjb2xvciA9ICJOb3JtYWxpemVkIFBEIFBSUyIpKwogICAgICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwKSkKICAgIHAyIDwtIGdncGxvdChjdXJfcGxvdCAlPiUgbXV0YXRlKFBEID0gaWZlbHNlKFBEID09IDEsICJDQVNFIiwgIkNPTlRST0wiKSksIGFlcyhmYWN0b3IocG9zKSwgdmFsdWUsIGNvbG9yID0gUEQpKSArCiAgICAgIGdlb21fYm94cGxvdChwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKDAuNzUpKSArCiAgICAgIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjYXNlX2NvbnRyb2wpICsKICAgICAgdGhlbWVfbWluaW1hbCgpICsKICAgICAgc3RhdF9zdW1tYXJ5KGFlcyhncm91cCA9IFBEKSwgZnVuID0gbWVhbiwgZ2VvbSA9ICJsaW5lIikgKwogICAgICBsYWJzKHRpdGxlID0gdW5pcXVlKGN1cl9wbG90JERNUikseD0iUE9TIix5PWJxdW90ZSgiTWV0aHlsYXRpb24ifmJldGEpLGNvbG9yID0gIlBEIHN0YXR1cyIpICsKICAgICAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCkpCiAgICBwcmludChwMSkKICAgIHByaW50KHAyKQogIH0KfQoKcGxvdF9kbXJzKGRtcl9jcm9zcywgcHJzX2Fubm90LCBwcnNfbWF0LG12YWx1ZXMsIHJldihjKCJncmF5ODAiLCAiZ3JheTQwIikpKQpwbG90X2RtcnMoZG1yX21hbGVzLHByc19hbm5vdF9tYWxlLHByc19tYXRfbWFsZSwgbXZhbHVlc19tYWxlLHJldihjKCJsaWdodCBibHVlIiwgImxpZ2h0Ymx1ZTQiKSkpCnBsb3RfZG1ycyhkbXJfZmVtYWxlLCBwcnNfYW5ub3RfZmVtYWxlLCBwcnNfbWF0X2ZlbWFsZSwgbXZhbHVlc19mZW1hbGUscmV2KGMoImxpZ2h0cGluayIsICJsaWdodHBpbms0IikpKQpgYGAKCgpgYGB7cn0KZG1yX2Nyb3NzCmRtcl9tYWxlcwpkbXJfZmVtYWxlCmBgYAoK